#include "eqopwidget.h"

EqOperator::EqOperator(const int &index, const EQ &eq, QWidget *parent)
    : QObject{parent}
    , m_index{index}
    , m_eq{eq}
    , m_lastGain{EQ_GAIN_DEFAULT}
{
    checkBox = new ACheckBox(QString::number(index + 1), parent);
    freqSpinBox = new ASpinBox(parent);
    qSpinBox = new QValueSpinBox(parent);
    gainSpinBox = new ADoubleSpinBox(parent);
    typeComboBox = new AComboBox(parent);

    checkBox->setFixedWidth(40);

    freqSpinBox->setRange(EQ_FREQUENCY_MIN, EQ_FREQUENCY_MAX);

    gainSpinBox->setRange(EQ_GAIN_MIN, EQ_GAIN_MAX);
    gainSpinBox->setSingleStep(EQ_GAIN_STEP);
    gainSpinBox->setDecimals(EQ_GAIN_DECIMAL);

    typeComboBox->setFixedWidth(DevEnvParam::CTRL_FIX_WIDTH);
    typeComboBox->addItem(tr(LABEL_PEQ));
    typeComboBox->addItem(tr(LABEL_LSEQ));
    typeComboBox->addItem(tr(LABEL_HSEQ));
    typeComboBox->addItem(tr(LABEL_ALLPASS_1));
    typeComboBox->addItem(tr(LABEL_ALLPASS_2));

    connect(checkBox, &QCheckBox::clicked, this, &EqOperator::checkBoxClicked);
    connect(freqSpinBox, QOverload<int>::of(&ASpinBox::valueChanged), this, &EqOperator::valueChanged);
    connect(qSpinBox, QOverload<int>::of(&ASpinBox::valueChanged), this, &EqOperator::valueChanged);
    connect(gainSpinBox, QOverload<double>::of(&ADoubleSpinBox::valueChanged), this, &EqOperator::gainSpinBoxChanged);
    connect(typeComboBox, QOverload<int>::of(&AComboBox::currentIndexChanged), this, &EqOperator::typeComboBoxIndexChanged);
}

EQ EqOperator::value() const
{
    EQ eq;
    eq.freq = freqSpinBox->value();
    eq.type = static_cast<EQType>(typeComboBox->currentIndex());
    eq.bw = qSpinBox->value();
    eq.gain = gainSpinBox->value();
    return eq;
}

bool EqOperator::bypass() const
{
    return checkBox->isChecked();
}

void EqOperator::set(const EQ &eq, bool init)
{
    setBlockSignals(true);

    freqSpinBox->setValue(eq.freq);
    qSpinBox->setValue(eq.bw);
    gainSpinBox->setValue(eq.gain);
    typeComboBox->setCurrentIndex(static_cast<int>(eq.type));
    checkBox->setChecked(EQ_GAIN_DEFAULT == gainSpinBox->value());

    setBlockSignals(false);

    emit stateChanged(m_index, value(), init);
}

void EqOperator::reset()
{
    set(m_eq, false);
}

void EqOperator::setBypass(bool checked)
{
    emit checkBox->clicked(checked);
}

void EqOperator::valueChanged()
{
    emit stateChanged(m_index, value(), false);
}

void EqOperator::gainSpinBoxChanged(const double &value)
{
    if (value < 0 && std::abs(value) < 1e-12) {
        gainSpinBox->blockSignals(true);
        gainSpinBox->setValue(0.0);
        gainSpinBox->blockSignals(false);
    }
    checkBox->setChecked(EQ_GAIN_DEFAULT == gainSpinBox->value());
    valueChanged();
}

void EqOperator::checkBoxClicked(bool checked)
{
    if (checked) {
        m_lastGain = gainSpinBox->value();
        gainSpinBox->setValue(EQ_GAIN_DEFAULT);
    }
    else {
        if (EQ_GAIN_DEFAULT == gainSpinBox->value()) {
            checkBox->setChecked(true);
        }
        gainSpinBox->setValue(m_lastGain);
    }
}

void EqOperator::typeComboBoxIndexChanged(const int &index)
{
    switch (static_cast<EQType>(index)) {
    case EQType::PEQ:
        checkBox->setEnabled(true);
        qSpinBox->setEnabled(true);
        gainSpinBox->setEnabled(true);
        break;
    case EQType::Hi_Shelf:
    case EQType::Lo_Shelf:
        qSpinBox->setEnabled(false);
        gainSpinBox->setEnabled(true);
        break;
    case EQType::ALLPASS_90:
    case EQType::ALLPASS_180:
        checkBox->setEnabled(false);
        qSpinBox->setEnabled(false);
        gainSpinBox->setEnabled(false);
        break;
    default:
        break;
    }
    valueChanged();
}

void EqOperator::setBlockSignals(bool block)
{
    checkBox->blockSignals(block);
    freqSpinBox->blockSignals(block);
    qSpinBox->blockSignals(block);
    gainSpinBox->blockSignals(block);
    typeComboBox->blockSignals(block);
}


EqOpWidget::EqOpWidget(const QList<EQ> &list, QWidget *parent)
    : AGroupBox{tr(LABEL_EQUALIZER), parent}
{
    scrollArea = new AScrollArea(this);
    widget = new AWidget(this);
    resetButton = new APushButton(tr(LABEL_RESET), this);
    bypassButton = new APushButton(tr(LABEL_BYPASS), this);

    auto layout = new QVBoxLayout(this);

    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(2);
    layout->addWidget(scrollArea);

    scrollArea->setFixedWidth(440);
    scrollArea->setWidget(widget);
    scrollArea->setWidgetResizable(true);

    bypassButton->setCheckable(true);

    auto wLayout = new QGridLayout(widget);
    widget->setLayout(wLayout);
    wLayout->setHorizontalSpacing(5 * ratio());
    wLayout->setVerticalSpacing(3 * ratio());

    wLayout->addWidget(new ALabel(tr(LABEL_BYPASS), this), 0, 0, Qt::AlignRight);
    wLayout->addWidget(new ALabel(tr(LABEL_FREQ), this), 0, 1, Qt::AlignHCenter);
    wLayout->addWidget(new ALabel(tr(LABEL_Q_VALUE), this), 0, 2, Qt::AlignHCenter);
    wLayout->addWidget(new ALabel(tr(LABEL_GAIN), this), 0, 3, Qt::AlignHCenter);
    wLayout->addWidget(new ALabel(tr(LABEL_TYPE), this), 0, 4, Qt::AlignHCenter);

    for (int i = 1; i <= list.size(); ++i) {
        auto op = new EqOperator(i - 1, list.at(i - 1), this);
        connect(op, &EqOperator::stateChanged, this, &EqOpWidget::stateChanged);
        wLayout->addWidget(op->checkBox, i, 0);
        wLayout->addWidget(op->freqSpinBox, i, 1);
        wLayout->addWidget(op->qSpinBox, i, 2);
        wLayout->addWidget(op->gainSpinBox, i, 3);
        wLayout->addWidget(op->typeComboBox, i, 4);
        m_opList.append(op);
    }
    wLayout->addWidget(resetButton, list.size() + 1, 3);
    wLayout->addWidget(bypassButton, list.size() + 1, 4);

    connect(resetButton, &APushButton::clicked, this, &EqOpWidget::reset);

    connect(bypassButton, &APushButton::toggled, this, &EqOpWidget::bypassClicked);
}

void EqOpWidget::set(const int &index, const EQ &eq, bool init)
{
    if (index > -1 && index < m_opList.size()) {
        m_opList[index]->set(eq, init);
    }
}

void EqOpWidget::reset()
{
    if (QMessageBox::question(this, tr("Tip"), tr("Reset all equalizers?")) == QMessageBox::Yes) {
        for (auto it = m_opList.begin(); it != m_opList.end(); ++it) {
            (*it)->reset();
        }
    }
}

void EqOpWidget::bypassClicked(bool checked)
{
    if (checked) {
        bypassButton->setText(tr(LABEL_UNBYPASS));
    }
    else {
        bypassButton->setText(tr(LABEL_BYPASS));
    }
    for (auto it = m_opList.begin(); it != m_opList.end(); ++it) {
        (*it)->setBypass(checked);
    }
}



